package com.cs410.collabwriting.servlets;

import java.io.IOException;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.json.JSONObject;

import com.cs410.collabwriting.connectors.SessionManager;
import com.cs410.collabwriting.main.Prompt;
import com.cs410.collabwriting.main.Story;
import com.cs410.collabwriting.main.StoryManager;
import com.cs410.collabwriting.main.Storylist;
import com.cs410.collabwriting.main.TagManager;
import com.cs410.collabwriting.main.User;
import com.cs410.collabwriting.main.UserManager;
import com.cs410.collabwriting.tools.LogManager;

/**
 * Servlet implementation class CreateHandler
 */
@WebServlet("/create")
public class CreateHandler extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CreateHandler() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String object = request.getParameter("object");
		JSONObject json = new JSONObject();
		if( SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() ) != null ) {
			if( object != null ) {
				if( object.compareToIgnoreCase("story") == 0 ) {
					json = createStoryHandler( json, request, response );
				} else if ( object.compareTo("prompt") == 0 ) {
					json = createPromptHandler( json, request, response );
				} else if( object.compareTo("post") == 0 ) {
					json = createNewPost( json, request, response );
				} else if( object.compareTo("upvote") == 0 ) {
					json = createNewUpvote( json, request, response );
				} else if( object.compareTo("comment") == 0 ) {
					json = createNewComment( json, request, response );
				} else if( object.compareTo("storylist") == 0 ) {
                    json = createNewStorylist( json, request, response );
				} else if( object.compareTo("storysub") == 0 ) {
					json = createNewStorySub( json, request, response );
				} else if( object.compareTo("usersub") == 0 ) {
					json = createNewUserSub( json, request, response );
				} else if( object.compareToIgnoreCase("sharestorylist") == 0 ) {
					json = shareStorylist( json, request, response );
				} else {
					try {
						json.put("error", "true");
						json.put("reason", "Invalid Object Creation : " + object + " does not exist");
					} catch (JSONException e) {
						
					}
				}
			} else {
				try {
					json.put("error", "true");
					json.put("reason", "No Object specified for creation!");
				} catch (JSONException e) {
					
				}
			}
		} else if( object.compareTo("user") == 0 ) {
			json = createNewUser( json, request, response );
		} else if( object.compareTo("activate") == 0 ) {
			json = activateUser( json, request, response );
		} else {
			try {
				json.put("error","true");
				json.put("reason", "Not Authorized. Please Log In and Try Again!");
			} catch ( JSONException e ) {
				
			}
		}
		response.getWriter().print( json.toString() );
	}

    protected JSONObject shareStorylist(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
        User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
        String listid = request.getParameter("listid");
        String storylistname = StoryManager.getInstance().getStorylistNameFromId(listid);
        String email = request.getParameter("email");
        try {
        	if( email != null && !email.isEmpty()) {
        		try {
        			shareStorylistWithEmail(user, email, listid, storylistname);
        			json.put("error","false");
        			json.put("reason","Email sent!");
        		} catch (Exception 	e) {
        			LogManager.logError( "[CreateHandler] -- " + e.getMessage() );
        		}
        	} else {
        		json.put("error","true");
        		json.put("reason","Invalid email, please try again");
        	}
        } catch (JSONException e ) {
            
        }
        return json;
    }
	
    //activate user after the user clicks the link on the email
    protected JSONObject activateUser(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
    	String username = request.getParameter("username");
        String key = request.getParameter("key");
		try {
			if( username != null && key != null && !username.isEmpty() && !key.isEmpty() ) {
				User user = UserManager.getInstance().getUser( username );
				if ( user != null ) {
						try {
							if (user.activateUser(username, key)) {
								json.put("error","false");
								response.sendRedirect("/writeonproject/home?page=activate_success");
							} else {
								json.put("error", "true");
								json.put("reason", "Activation key did not match.");
								response.sendRedirect("/writeonproject/home?page=activate_fail");
							}
						} catch (Exception e) {
							LogManager.logError( "[CreateHandler] -- " + e.getMessage() );
						}
						
				} else {
					json.put("error", "true");
					json.put("reason", "User does not exist.");
				}
				
			} else {
				json.put("error", "true" );
				json.put("reason", "Must have valid username and activation key.");
			}
		} catch (JSONException e) {
			
		}
				
		return json;
    }
    
    protected JSONObject createNewStorylist(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
        User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
        String name = request.getParameter("name");
        
        try {
        	if( name != null && !name.isEmpty()) {
        		if ( StoryManager.getInstance().createStorylist( name, user.getUserID() ) ) {
        			json.put("error","false");
        		} else {
        			json.put("error","true");
        			json.put("reason","Storylist could not be created");
        		}
        	} else {
        		json.put("error","true");
        		json.put("reason","Name cannot be empty");
        	}
        } catch (JSONException e ) {
            
        }
        return json;
    }

	protected JSONObject createNewUserSub(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		String userid = request.getParameter("userid");
		try {
			if( userid != null && userid.isEmpty() == false ) {
				user.subscribeToWriter( userid );
				json.put("error","false");
			} else {
				json.put("error", "true");
				json.put("reason","could not find user to subsribe to");
			}
		} catch (JSONException e) {
			
		}
		return json;
	}

	protected JSONObject createNewStorySub(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		String storyid = request.getParameter("storyid");
		try {
			if( storyid != null && storyid.isEmpty() == false ) {
				user.subscribeToStory( Integer.parseInt( storyid ) );
				json.put("error","false");
			} else {
				json.put("error","true");
				json.put("reason","storyid cannot be empty");
			}
		} catch ( JSONException e ) {
			
		}
		return json;
	}

	protected JSONObject createNewComment(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		String storyid = request.getParameter("storyid");
		String comment = request.getParameter("comment");
		try {
			if( storyid != null && !storyid.isEmpty() && comment != null && !comment.isEmpty()) {
				Story story = StoryManager.getInstance().getStoryByID( Integer.parseInt( storyid ) );
				if ( story.comment( user.getUserID(), comment ) ) {
					json.put("error","false");
				} else {
					json.put("error","true");
					json.put("reason", "comment could not be created");
				}
			} else {
				json.put("error","true");
				json.put("reason","storyid can not be empty");
			}
		} catch (JSONException e ) {
			
		}
		return json;
	}

	protected JSONObject createNewUpvote(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		String storyid = request.getParameter("storyid");
		try {
			if( storyid != null && !storyid.isEmpty() ) {
				Story story = StoryManager.getInstance().getStoryByID( Integer.parseInt( storyid ) );
					if (story.upvoteStory( user.getUserID() )) {
						json.put("error","false");
					} else {
						json.put("error","true");
						json.put("reason", "story could not be upvoted");
					}
			} else {
				json.put("error","true");
				json.put("reason","storyid cannot be empty");
			}
		} catch (JSONException e ) {
			
		}
		return json;
	}

	protected JSONObject createNewPost(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		String postRecv = request.getParameter("post");
		String storyID = request.getParameter("storyid");
		try {
			if( postRecv != null && !postRecv.isEmpty() && !postRecv.equals("") ) {
				if( storyID != null ) {
					Story story = StoryManager.getInstance().getStoryByID( Integer.parseInt( storyID ) );
						if (story.contributePost( user.getUserID(), postRecv )) {
							String tagList = request.getParameter("tags");
							if( tagList != null ) {
								String[] tags = tagList.split(",");
								TagManager.getInstance().updateTags( story.getStoryID(), user.getUserID(), tags);
								json.put("error","false");
							}
						} else {
							json.put("error","true");
							json.put("reason","Could not post to story");						        
						}
				} else {
					json.put("error","true");
					json.put("reason","no story to contribute to!");
				}
			} else {
				json.put("error","true");
				json.put("reason","Empty posts are not allowed!");
			}
		} catch (JSONException e) {
			
		}
		return json;
	}

	
	protected JSONObject createNewUser(JSONObject json, HttpServletRequest request, HttpServletResponse response) {
		String username = request.getParameter("username"); 
		String password = request.getParameter("password");
		String email = request.getParameter("email");
		String firstname = request.getParameter("firstname");
		String lastname = request.getParameter("lastname");
		String location = request.getParameter("location");
		String gender = request.getParameter("gender");
		String bio = request.getParameter("bio");
		
		try {
			if( username != null && password != null && email != null &&
					!username.isEmpty() && !password.isEmpty() && !email.isEmpty() ) {
				User user = UserManager.getInstance().addUser( username, password, email );
				if ( user != null ) {
					json.put("error","false");
				} else {
					json.put("error","true");
					json.put("reason", "Activate Key generate failed");

				}
				if ( user != null ) {
					json.put("error","false");
					
					
					// a lot of setting variables if they exist
					if (firstname != null) {
						user.setFirstName(firstname);
					}
					if (lastname != null) {
						user.setLastName(lastname);
					}
					if (location != null) {
						user.setLocation(location);
					}
					if (gender != null) {
						user.setGender(gender);
					}
					if (bio != null) {
						user.setBiography(bio);
					}
					try {
	            		sendActivationEmail(user);
						json.put("error","false");
						json.put("reason","Email sent!");
	            	} catch (Exception 	e) {
	            		LogManager.logError("[CreateHandler] " + e.getMessage() );
	            	}
				} else {
					json.put("error", "true");
					json.put("reason", "Username is already taken.");
				}

			} else {
				json.put("error", "true" );
				json.put("reason", "Must have valid username, password and email.");
			}
		} catch (JSONException e) {
			
		}
				
		return json;
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}
	
	protected JSONObject createStoryHandler( JSONObject json, HttpServletRequest request, HttpServletResponse response )  {
		String promptID = request.getParameter("promptid");
		String title = request.getParameter("title");
		String post = request.getParameter("post");
		
		User user = SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() );
		Prompt aPrompt = null;
		if( promptID != null  ) {
			aPrompt = new Prompt( promptID );
			if( !aPrompt.isActive() ) {
				aPrompt =null;
			}
		}
		Story story = StoryManager.getInstance().createStory( title, user.getUserID(), aPrompt);
		
		String tagList = request.getParameter("tags");
		if( tagList != null ) {
			String[] tags = tagList.split(",");
		for( int i = 0; i < tags.length; i++ ) {
			TagManager.getInstance().addTag( story.getStoryID(), user.getUserID(), tags[i] );
		}
		}
		try {
			if( story == null ) {
				json.put("error", "true");
				json.put("reason", "Failed to Create Story");
			} else {
				story.contributePost( user.getUserID(), post );
				json.put("error", "false");
				json.put("storyid", story.getStoryID() );
			}
		} catch ( JSONException e ) {
			
		}
		return json;
	}
	
	protected JSONObject createPromptHandler( JSONObject json, HttpServletRequest request, HttpServletResponse response ) {
		String url = request.getParameter("imgurl");
		String text = request.getParameter("text");
		
		if( url != null && url.isEmpty() ) { url = null; }
		if( text != null && text.isEmpty() ) { text = null; }
		Prompt aPrompt = new Prompt();
		aPrompt.setImageFilePath( url );
		aPrompt.setTextPrompt( text );
		aPrompt.setUserID( SessionManager.getUserIDForJSessionID( request.getRequestedSessionId() ).getUserID() );
		boolean created = aPrompt.create();
		
		try {
			if( created ) {
				json.put("error", "false");
			} else {
				json.put("error", "true");
				json.put("reason", "Failed to Create Prompt" );
			}
		} catch ( JSONException e ) {
			
		}
		
		return json;
	}

	/*
	 * JAVA MAIL CODE ADAPTED FROM :
	 * http://www.java2s.com/Code/Java/Network-Protocol/SendmailusingGMAIL.htm
	 */
	protected void sendActivationEmail(User user) throws Exception {
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.auth", "true");
		props.put("mail.debig","true");
		props.put("mail.smtp.port", "465" );
		props.put("mail.smtp.socketFactory.port","465");
		props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.put("mail.smtp.socketFactory.fallback","false");
		
		Session session = Session.getDefaultInstance( props, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("cs410writeon","ubccpsc410");
			}
		});
		session.setDebug( true );
		Message message = new MimeMessage(session);
		InternetAddress from = new InternetAddress("cs410writeon@gmail.com");
		message.setFrom( from );
		InternetAddress addressTo = new InternetAddress( user.getEmailAddress() );
		message.setRecipient( Message.RecipientType.TO, addressTo );
		message.setSubject("CS410 Write-on! Activation Email for " + user.getUserID() );
		String text = "You need to validate your email and activate your account, " + user.getUserID() + "! Click "
				+ "<a href=\"http://localhost:8080/writeonproject/create?object=activate&username="
				+ user.getUserID() + "&key=" + user.getActivateKey() + "\">here</a> to activate it.";
		message.setContent(text, "text/html");
		Transport.send( message );
	}
	
	/*
	 * JAVA MAIL CODE ADAPTED FROM :
	 * http://www.java2s.com/Code/Java/Network-Protocol/SendmailusingGMAIL.htm
	 */
	protected void shareStorylistWithEmail(User user, String email, String listid, String storylistname) throws Exception {
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.auth", "true");
		props.put("mail.debig","true");
		props.put("mail.smtp.port", "465" );
		props.put("mail.smtp.socketFactory.port","465");
		props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.put("mail.smtp.socketFactory.fallback","false");
		
		Session session = Session.getDefaultInstance( props, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("cs410writeon","ubccpsc410");
			}
		});
		session.setDebug( true );
		Message message = new MimeMessage(session);
		InternetAddress from = new InternetAddress("cs410writeon@gmail.com");
		message.setFrom( from );
		InternetAddress addressTo = new InternetAddress( email );
		message.setRecipient( Message.RecipientType.TO, addressTo );
		message.setSubject(user.getUserID() + " wants to share a Storylist!" );
		String text = user.getUserID() + " wants to share the following storylist: "
				+ "<a href=\"http://localhost:8080/writeonproject/home?page=storylist&listid="
				+ listid + "\">" + storylistname + "</a>.";
		message.setContent(text, "text/html");
		Transport.send( message );
	}
	
}